home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / cl_demo.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  8KB  |  389 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20.  
  21. #include "quakedef.h"
  22.  
  23. void CL_FinishTimeDemo (void);
  24.  
  25. /*
  26. ==============================================================================
  27.  
  28. DEMO CODE
  29.  
  30. When a demo is playing back, all NET_SendMessages are skipped, and
  31. NET_GetMessages are read from the demo file.
  32.  
  33. Whenever cl.time gets past the last received message, another message is
  34. read from the demo file.
  35. ==============================================================================
  36. */
  37.  
  38. /*
  39. ==============
  40. CL_StopPlayback
  41.  
  42. Called when a demo file runs out, or the user starts a game
  43. ==============
  44. */
  45. void CL_StopPlayback (void)
  46. {
  47.     if (!cls.demoplayback)
  48.         return;
  49.  
  50.     fclose (cls.demofile);
  51.     cls.demoplayback = false;
  52.     cls.demofile = NULL;
  53.     cls.state = ca_disconnected;
  54.  
  55.     if (cls.timedemo || cls.timedemo2)
  56.         CL_FinishTimeDemo ();
  57. }
  58.  
  59. /*
  60. ====================
  61. CL_WriteDemoMessage
  62.  
  63. Dumps the current net message, prefixed by the length and view angles
  64. ====================
  65. */
  66. void CL_WriteDemoMessage (void)
  67. {
  68.     int        len;
  69.     int        i;
  70.     float    f;
  71.  
  72.     len = LittleLong (net_message.cursize);
  73.     fwrite (&len, 4, 1, cls.demofile);
  74.     for (i=0 ; i<3 ; i++)
  75.     {
  76.         f = LittleFloat (cl.viewangles[i]);
  77.         fwrite (&f, 4, 1, cls.demofile);
  78.     }
  79.     fwrite (net_message.data, net_message.cursize, 1, cls.demofile);
  80.     fflush (cls.demofile);
  81. }
  82.  
  83. /*
  84. ====================
  85. CL_GetMessage
  86.  
  87. Handles recording and playback of demos, on top of NET_ code
  88. ====================
  89. */
  90. int CL_GetMessage (void)
  91. {
  92.     int        r, i;
  93.     float    f;
  94.  
  95.     if    (cls.demoplayback)
  96.     {
  97.     // decide if it is time to grab the next message        
  98.         if (cls.signon == SIGNONS)    // allways grab until fully connected
  99.         {
  100.             if (cls.timedemo || cls.timedemo2)
  101.             {
  102.                 if (host_framecount == cls.td_lastframe)
  103.                     return 0;        // allready read this frame's message
  104.                 cls.td_lastframe = host_framecount;
  105.             // if this is the second frame, grab the real td_starttime
  106.             // so the bogus time on the first frame doesn't count
  107.                 if (host_framecount == cls.td_startframe + 1)
  108.                     cls.td_starttime = realtime;
  109.             }
  110.             else if ( /* cl.time > 0 && */ cl.time <= cl.mtime[0])
  111.             {
  112.                     return 0;        // don't need another message yet
  113.             }
  114.         }
  115.         
  116.     // get the next message
  117.         fread (&net_message.cursize, 4, 1, cls.demofile);
  118.         VectorCopy (cl.mviewangles[0], cl.mviewangles[1]);
  119.         for (i=0 ; i<3 ; i++)
  120.         {
  121.             r = fread (&f, 4, 1, cls.demofile);
  122.             cl.mviewangles[0][i] = LittleFloat (f);
  123.         }
  124.         
  125.         net_message.cursize = LittleLong (net_message.cursize);
  126.         if (net_message.cursize > MAX_MSGLEN)
  127.             Sys_Error ("Demo message > MAX_MSGLEN");
  128.         r = fread (net_message.data, net_message.cursize, 1, cls.demofile);
  129.         if (r != 1)
  130.         {
  131.             CL_StopPlayback ();
  132.             return 0;
  133.         }
  134.     
  135.         return 1;
  136.     }
  137.  
  138.     while (1)
  139.     {
  140.         r = NET_GetMessage (cls.netcon);
  141.         
  142.         if (r != 1 && r != 2)
  143.             return r;
  144.     
  145.     // discard nop keepalive message
  146.         if (net_message.cursize == 1 && net_message.data[0] == svc_nop)
  147.             Con_Printf ("<-- server to client keepalive\n");
  148.         else
  149.             break;
  150.     }
  151.  
  152.     if (cls.demorecording)
  153.         CL_WriteDemoMessage ();
  154.     
  155.     return r;
  156. }
  157.  
  158.  
  159. /*
  160. ====================
  161. CL_Stop_f
  162.  
  163. stop recording a demo
  164. ====================
  165. */
  166. void CL_Stop_f (void)
  167. {
  168.     if (cmd_source != src_command)
  169.         return;
  170.  
  171.     if (!cls.demorecording)
  172.     {
  173.         Con_Printf ("Not recording a demo.\n");
  174.         return;
  175.     }
  176.  
  177. // write a disconnect message to the demo file
  178.     SZ_Clear (&net_message);
  179.     MSG_WriteByte (&net_message, svc_disconnect);
  180.     CL_WriteDemoMessage ();
  181.  
  182. // finish up
  183.     fclose (cls.demofile);
  184.     cls.demofile = NULL;
  185.     cls.demorecording = false;
  186.     Con_Printf ("Completed demo\n");
  187. }
  188.  
  189. /*
  190. ====================
  191. CL_Record_f
  192.  
  193. record <demoname> <map> [cd track]
  194. ====================
  195. */
  196. void CL_Record_f (void)
  197. {
  198.     int        c;
  199.     char    name[MAX_OSPATH];
  200.     int        track;
  201.  
  202.     if (cmd_source != src_command)
  203.         return;
  204.  
  205.     c = Cmd_Argc();
  206.     if (c != 2 && c != 3 && c != 4)
  207.     {
  208.         Con_Printf ("record <demoname> [<map> [cd track]]\n");
  209.         return;
  210.     }
  211.  
  212.     if (strstr(Cmd_Argv(1), ".."))
  213.     {
  214.         Con_Printf ("Relative pathnames are not allowed.\n");
  215.         return;
  216.     }
  217.  
  218.     if (c == 2 && cls.state == ca_connected)
  219.     {
  220.         Con_Printf("Can not record - already connected to server\nClient demo recording must be started before connecting\n");
  221.         return;
  222.     }
  223.  
  224. // write the forced cd track number, or -1
  225.     if (c == 4)
  226.     {
  227.         track = atoi(Cmd_Argv(3));
  228.         Con_Printf ("Forcing CD track to %i\n", cls.forcetrack);
  229.     }
  230.     else
  231.         track = -1;    
  232.  
  233.     sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1));
  234.     
  235. //
  236. // start the map up
  237. //
  238.     if (c > 2)
  239.         Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command);
  240.     
  241. //
  242. // open the demo file
  243. //
  244.     COM_DefaultExtension (name, ".dem");
  245.  
  246.     Con_Printf ("recording to %s.\n", name);
  247.     cls.demofile = fopen (name, "wb");
  248.     if (!cls.demofile)
  249.     {
  250.         Con_Printf ("ERROR: couldn't open.\n");
  251.         return;
  252.     }
  253.  
  254.     cls.forcetrack = track;
  255.     fprintf (cls.demofile, "%i\n", cls.forcetrack);
  256.     
  257.     cls.demorecording = true;
  258. }
  259.  
  260.  
  261. /*
  262. ====================
  263. CL_PlayDemo_f
  264.  
  265. play [demoname]
  266. ====================
  267. */
  268. void CL_PlayDemo_f (void)
  269. {
  270.     char    name[256];
  271.     int c;
  272.     qboolean neg = false;
  273.  
  274.     if (cmd_source != src_command)
  275.         return;
  276.  
  277.     if (Cmd_Argc() != 2)
  278.     {
  279.         Con_Printf ("play <demoname> : plays a demo\n");
  280.         return;
  281.     }
  282.  
  283. //
  284. // disconnect from server
  285. //
  286.     CL_Disconnect ();
  287.     
  288. //
  289. // open the demo file
  290. //
  291.     strcpy (name, Cmd_Argv(1));
  292.     COM_DefaultExtension (name, ".dem");
  293.  
  294.     Con_Printf ("Playing demo from %s.\n", name);
  295.     COM_FOpenFile (name, &cls.demofile);
  296.     if (!cls.demofile)
  297.     {
  298.         Con_Printf ("ERROR: couldn't open.\n");
  299.         cls.demonum = -1;        // stop demo loop
  300.         return;
  301.     }
  302.  
  303.     cls.demoplayback = true;
  304.     cls.state = ca_connected;
  305.     cls.forcetrack = 0;
  306.  
  307.     while ((c = getc(cls.demofile)) != '\n')
  308.         if (c == '-')
  309.             neg = true;
  310.         else
  311.             cls.forcetrack = cls.forcetrack * 10 + (c - '0');
  312.  
  313.     if (neg)
  314.         cls.forcetrack = -cls.forcetrack;
  315. // ZOID, fscanf is evil
  316. //    fscanf (cls.demofile, "%i\n", &cls.forcetrack);
  317. }
  318.  
  319. /*
  320. ====================
  321. CL_FinishTimeDemo
  322.  
  323. ====================
  324. */
  325. void CL_FinishTimeDemo (void)
  326. {
  327.     int        frames;
  328.     float    time;
  329.  
  330.     cls.timedemo = false;
  331.     cls.timedemo2 = false;
  332.  
  333. // the first frame didn't count
  334.     frames = (host_framecount - cls.td_startframe) - 1;
  335.     time = realtime - cls.td_starttime;
  336.     if (!time)
  337.         time = 1;
  338.     Con_Printf ("%i frames %5.1f seconds %5.1f fps\n", frames, time, frames/time);
  339. }
  340.  
  341. /*
  342. ====================
  343. CL_TimeDemo_f
  344.  
  345. timedemo [demoname]
  346. ====================
  347. */
  348. void CL_TimeDemo_f (void)
  349. {
  350.     if (cmd_source != src_command)
  351.         return;
  352.  
  353.     if (Cmd_Argc() != 2)
  354.     {
  355.         Con_Printf ("timedemo <demoname> : gets demo speeds\n");
  356.         return;
  357.     }
  358.  
  359.     CL_PlayDemo_f ();
  360.     
  361. // cls.td_starttime will be grabbed at the second frame of the demo, so
  362. // all the loading time doesn't get counted
  363.     
  364.     cls.timedemo = true;
  365.     cls.td_startframe = host_framecount;
  366.     cls.td_lastframe = -1;        // get a new message this frame
  367. }
  368.  
  369. void CL_TimeDemo2_f (void)
  370. {
  371.     if (cmd_source != src_command)
  372.         return;
  373.  
  374.     if (Cmd_Argc() != 2)
  375.     {
  376.         Con_Printf ("timedemo2 <demoname> : gets demo speeds\n");
  377.         return;
  378.     }
  379.  
  380.     CL_PlayDemo_f ();
  381.     
  382. // cls.td_starttime will be grabbed at the second frame of the demo, so
  383. // all the loading time doesn't get counted
  384.     
  385.     cls.timedemo2 = true;
  386.     cls.td_startframe = host_framecount;
  387.     cls.td_lastframe = -1;        // get a new message this frame
  388. }
  389.